package com.spark.lola.logistics.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.spark.lola.logistics.constant.LogisticsConstant;
import com.spark.lola.logistics.entity.*;
import com.spark.lola.logistics.mapper.*;
import com.spark.lola.logistics.service.ExpensesCategoryService;
import com.spark.lola.logistics.service.ExpensesDetailService;
import com.spark.lola.logistics.service.ExpensesInfoService;
import com.spark.lola.logistics.service.LogisticsOrderProductService;
import com.spark.lola.logistics.vo.DriverVo;
import com.spark.lola.logistics.vo.ExpensesAnalyzeVo;
import com.spark.lola.logistics.vo.ExpensesDetailVo;
import com.spark.lola.statistics.dto.DealExpensesChange;
import com.spark.lola.support.common.constant.CommonConstant;
import com.spark.lola.support.common.entity.ShiroUser;
import com.spark.lola.support.common.util.DataBeanUtils;
import com.spark.lola.support.common.util.NumberUtil;
import com.spark.lola.support.mybatis.entity.PageParam;
import com.spark.lola.support.mybatis.entity.QueryParam;
import com.spark.lola.support.mybatis.service.impl.BaseServiceImpl;
import com.spark.lola.support.wms.cache.CollectionCache;
import com.spark.lola.support.wms.constant.KafkaTopic;
import com.spark.lola.support.wms.constant.OrderType;
import com.spark.lola.support.wms.dto.OrderDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author: Zhi-peng wang
 * @date: 2020/05/07 11:23
 * 货运支出单业务接口实现
 **/
@Service
public class ExpensesInfoServiceImpl extends BaseServiceImpl<ExpensesInfoMapper, ExpensesInfo> implements ExpensesInfoService {

    private static final Logger logger = LoggerFactory.getLogger(ExpensesInfoServiceImpl.class);

    @Autowired
    private ExpensesInfoMapper expensesInfoMapper;

    @Autowired
    private ExpensesDetailMapper expensesDetailMapper;

    @Autowired
    private ExpensesProcessMapper expensesProcessMapper;

    @Autowired
    private LogisticsOrderInfoMapper logisticsOrderInfoMapper;

    @Autowired
    private LogisticsOrderProcessMapper logisticsOrderProcessMapper;

    @Autowired
    private CarInfoMapper carInfoMapper;

    @Autowired
    private DriverInfoMapper driverInfoMapper;

    @Autowired
    private ExpensesDetailService expensesDetailService;

    @Autowired
    private ExpensesCategoryService expensesCategoryService;

    @Autowired
    private LogisticsOrderProductService logisticsOrderProductService;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Override
    public IPage<ExpensesInfo> findPage(QueryParam<ExpensesInfo> queryParam) {
        PageParam<ExpensesInfo> pageParam = queryParam.toPageParam();
        return expensesInfoMapper.findPage(pageParam.getPage(), pageParam.getEntityWrapper());
    }

    @Override
    public ExpensesInfo findInfo(long id) {
        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(id);
        if (expensesInfo != null) {
            List<ExpensesDetail> expensesDetailList = expensesDetailMapper.findByExpensesId(expensesInfo.getId());
            if (!CollectionUtils.isEmpty(expensesDetailList)) {
                expensesInfo.setExpensesDetailList(expensesDetailList);
            }
            // 里程信息
            if (expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.WAIT_AUDIT) {
                long carId = logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId());
                int preMileage = carInfoMapper.findMileageById(carId);
                expensesInfo.setPreMileage(preMileage);
            }
            expensesInfo.setSemitrailerNo(logisticsOrderInfoMapper.findSemitrailerNo(expensesInfo.getToOrderId()));
            // 借款信息
            DriverInfo driverInfo = getDriverInfo(expensesInfo.getEmpId());
            if (driverInfo != null) {
                expensesInfo.setBorrowingAmount(driverInfo.getBorrowingAmount());
                expensesInfo.setBorrowingTime(driverInfo.getBorrowingTime());
            }
            // 获取驾驶员信息
            ShiroUser shiroUser = CollectionCache.employees.get(expensesInfo.getEmpId());
            if (shiroUser != null) {
                DriverVo driverVo = new DriverVo();
                driverVo.setName(shiroUser.getRealName());
                driverVo.setPhone(shiroUser.getPhone());
                driverVo.setCarNo(carInfoMapper.findNoById(logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId())));
                expensesInfo.setDriverVo(driverVo);
            }
            // 获取直达车信息
            expensesInfo.setToOrderInfo(getOrderInfo(expensesInfo.getToOrderId()));
            // 获取回头车信息
            if (expensesInfo.getReturnOrderId() != null) {
                expensesInfo.setReturnOrderInfo(getOrderInfo(expensesInfo.getReturnOrderId()));
            }
            // 获取流程信息
            List<ExpensesProcess> expensesProcessList = expensesProcessMapper.findByExpensesId(id);
            expensesInfo.setExpensesProcessList(expensesProcessList);
        }
        return expensesInfo;
    }

    private OrderInfo getOrderInfo(long orderId) {
        // 货运单信息
        QueryWrapper<OrderInfo> wrapperOrder = new QueryWrapper<>();
        wrapperOrder.select("page_no,start_area,start_address,end_area,end_address");
        wrapperOrder.eq("id", orderId);
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectList(wrapperOrder).get(0);
        // 发货时间
        List<OrderProcess> orderProcessList = logisticsOrderProcessMapper.findNewest(orderId,
                LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS, LogisticsConstant.ProcessFlag.NEWEST);
        orderInfo.setOrderProcessList(orderProcessList);
        // 货运单货品信息
        QueryWrapper<OrderProduct> wrapperProduct = new QueryWrapper<>();
        wrapperProduct.select("name,weight");
        wrapperProduct.eq("order_id", orderId);
        List<OrderProduct> list = logisticsOrderProductService.list(wrapperProduct);
        orderInfo.setOrderProductList(list);
        return orderInfo;
    }

    private DriverInfo getDriverInfo(long empId) {
        QueryWrapper<DriverInfo> wrapper = new QueryWrapper<>();
        wrapper.select("id,borrowing_amount,borrowing_time,version");
        wrapper.eq("emp_id", empId);
        List<DriverInfo> list = driverInfoMapper.selectList(wrapper);
        return list.size() == 0 ? null : list.get(0);
    }

    @Override
    public ExpensesInfo addExpenses(ExpensesInfo expensesInfo, ShiroUser shiroUser) throws Exception {
        String logAction = LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_AUDIT);
        expensesInfo.setNo(NumberUtil.getOrderIdByTime("E"));
        expensesInfo.setEmpId(shiroUser.getId());
        logger.info("===={}货运支出单【{}】{}人【{}】===START===", logAction, expensesInfo.getNo(), logAction, shiroUser.getLoginNo());
        // 判断货运支出单绑定货运单唯一性
        if (expensesInfoMapper.countByOrderId(expensesInfo.getToOrderId(), LogisticsConstant.OrderLineType.TO_CAR) != 0) {
            logger.info("====添加货运支出单（直达车货运单已被绑定） 失败===END===");
            throw new Exception("直达车货运单已被绑定");
        }
        // 添加
        logger.info("====添加货运支出单基本信息===START===");
        if (!this.save(expensesInfo)) {
            logger.info("====添加货运支出单基本信息 失败===END===");
            throw new Exception("货运支出单基本信息添加失败");
        }
        // 此时将货运支出单记录支出单状态改为已存在
        updateOrderIsBind("直达车", expensesInfo.getToOrderNo(), expensesInfo.getToOrderId(), LogisticsConstant.ExpensesExists.YES_EXISTS);
        // 添加操作记录
        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser, expensesInfo.getStatus(), logAction);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendExpenseChange(expensesInfo, "支出单申请成功！", actionMsg);
                    }
                });
        logger.info("====添加货运支出单信息 成功===END===");
        return expensesInfo;
    }

    @Override
    public ExpensesInfo updateExpenses(ExpensesInfo expensesInfo, ShiroUser shiroUser) throws Exception {
        String logAction = LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT);
        ExpensesInfo model = expensesInfoMapper.selectById(expensesInfo.getId());
        logger.info("===={}货运支出单【{}】{}人【{}】===START===", logAction, model.getNo(), logAction, shiroUser.getLoginNo());
        // 只有待核算可修改
        if (model.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_AUDIT) {
            logger.info("====保存货运支出单（状态错误） 失败===END===");
            throw new Exception("未处于待核算状态");
        }
        // 判定信息健全
        List<ExpensesDetail> expensesDetailList = expensesInfo.getExpensesDetailList();
        if (CollectionUtils.isEmpty(expensesDetailList)) {
            logger.info("====未添加货运支出单详细信息===END===");
            throw new Exception("未添加货运支出单详细信息");
        }
        if (expensesInfo.getReturnOrderId() != null && expensesInfoMapper.countByOrderId(expensesInfo.getReturnOrderId(), LogisticsConstant.OrderLineType.RETURN_CAR) != 0) {
            logger.info("====添加货运支出单（回头车货运单已被绑定） 失败===END===");
            throw new Exception("回头车货运单已被绑定");
        }
        long carId = logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId());
        int preMileage = carInfoMapper.findMileageById(carId);
        if (preMileage >= expensesInfo.getNowMileage()) {
            throw new Exception("本次里程数填写错误!");
        }
        // 修改
        logger.info("====保存货运支出单基本信息===START===");
        // 非修改项置空
        model.setNo(null);
        model.setEmpId(null);
        model.setToOrderId(null);
        model.setToOrderNo(null);
        model.setReturnOrderId(null);
        model.setReturnOrderNo(null);
        model.setIsRejected(null);
        DataBeanUtils.buildUpdateBean(model, expensesInfo);
        model.setPreMileage(preMileage);
        model.setStatus(LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT);
        BigDecimal aveConsumption = model.getFuelConsumption()
                .divide(BigDecimal.valueOf(model.getNowMileage() - model.getPreMileage()), 3, BigDecimal.ROUND_HALF_UP);
        model.setAveConsumption(aveConsumption);
        model.setTotalFuel(model.getFuelConsumption().multiply(model.getFuelPrice()));
        // 借款金额比较
        // 借款信息
        DriverInfo driverInfo = getDriverInfo(expensesInfo.getEmpId());
        if (!driverInfo.getBorrowingAmount().equals(expensesInfo.getBorrowingAmount())) {
            driverInfo.setBorrowingAmount(expensesInfo.getBorrowingAmount());
            driverInfo.setBorrowingTime(expensesInfo.getBorrowingTime());
            if (driverInfoMapper.updateById(driverInfo) == 0) {
                logger.info("====更新借款信息 失败===END===");
                throw new Exception("更新借款信息失败");
            }
        }
        if (!this.updateById(model)) {
            logger.info("====保存货运支出单基本信息 失败===END===");
            throw new Exception("货运支出单基本信息保存失败");
        }
        // 此时将货运支出单记录支出单状态改为已存在
        if (expensesInfo.getReturnOrderId() != null) {
            updateOrderIsBind("回头车", expensesInfo.getReturnOrderNo(), expensesInfo.getReturnOrderId(), LogisticsConstant.ExpensesExists.YES_EXISTS);
        }
        // 修改里程
        if (carInfoMapper.updateMileageById(model.getNowMileage(), carId) == 0) {
            logger.info("====保存里程信息 失败===END===");
        }
        // 保存货运支出单详细信息
        BigDecimal totalCost = saveExpensesDetail(model.getId(), expensesDetailList);
        // 保存费用总额
        expensesInfoMapper.updateTotalCostById(totalCost, model.getId());
        // 添加操作记录
        String actionMsg = addExpensesProcess(model.getId(), model.getNo(), shiroUser, model.getStatus(), logAction);
        logger.info("====保存货运支出单信息 成功===END===");
        model.setTotalCost(totalCost);
        model.setExpensesDetailList(expensesDetailList);
//        DealStatisticsChange<Integer> dealStatisticsChange = new DealStatisticsChange<>(
//                new Date(), expensesInfo.getEmpId(), logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId()),
//                (expensesInfo.getNowMileage() - expensesInfo.getPreMileage()), expensesInfo.getRefundableFee().setScale(2, BigDecimal.ROUND_HALF_DOWN)
//        );
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
//                        // kafka推送-处理统计
//                        kafkaTemplate.send(KafkaTopic.STATISTICS_EXPENSES_CHANGE, "expenses", JSONObject.toJSONString(dealStatisticsChange));
                        // kafka推送
                        sendExpenseChange(model, shiroUser.getRealName() + "添加了支出单明细", actionMsg);
                    }
                });
        return model;
    }

    @Override
    public void deleteOrder(long expensesInfoId, ShiroUser shiroUser) throws Exception {
        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
        logger.info("====货运支出单【{}】删除操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
        if (!expensesInfo.getEmpId().equals(shiroUser.getId())) {
            logger.info("====货运支出单删除操作（非法操作） 失败===END===");
            throw new Exception("非法操作");
        }
        if (expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
            logger.info("====货运支出单删除操作（已完成禁止操作） 失败===END===");
            throw new Exception("已完成禁止删除");
        }
        // 删除流程信息
        logger.info("====删除货运支出单流程信息 ===START===");
        if (expensesProcessMapper.deleteByExpensesId(expensesInfoId) == 0) {
            logger.info("====货运支出单流程信息删除 失败===END===");
            throw new Exception("货运支出单流程信息删除失败");
        }
        logger.info("====货运支出单流程信息删除 成功===END===");
        // 删除详细信息
        logger.info("====删除货运支出单详细信息 ===START===");
        if (expensesDetailMapper.deleteByExpensesId(expensesInfo.getId()) == 0) {
            logger.info("====删除货运支出单详细信息 失败===END===");
            throw new Exception("删除货运支出单详细信息失败");
        }
        logger.info("====删除货运支出单详细信息 成功===END===");
        // 删除货运支出单信息
        logger.info("====删除货运支出单信息 ===START===");
        if (expensesDetailMapper.deleteById(expensesInfo.getId()) == 0) {
            logger.info("====删除货运支出单信息 失败===END===");
            throw new Exception("删除货运支出单信息失败");
        }
        logger.info("====删除货运支出单信息 成功===END===");
        // 此时将货运支出单记录支出单状态改为不存在
        updateOrderIsBind("直达车", expensesInfo.getToOrderNo(), expensesInfo.getToOrderId(), LogisticsConstant.ExpensesExists.NO_EXISTS);
        if (expensesInfo.getReturnOrderId() != null) {
            updateOrderIsBind("回头车", expensesInfo.getReturnOrderNo(), expensesInfo.getReturnOrderId(), LogisticsConstant.ExpensesExists.NO_EXISTS);
        }
        logger.info("====更新回头车货运单绑定状态 成功===END===");
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        ExpensesProcess expensesProcess = new ExpensesProcess();
                        expensesProcess.setActionCode(-3);
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        String nowDate = simpleDateFormat.format(new Date());
                        expensesProcess.setInfo(String.format("员工【%s】%s 进行【删除】操作", shiroUser.getRealName(), nowDate));
                        sendExpenseChange(expensesInfo, shiroUser.getRealName() + "删除了支出单", JSONObject.toJSONString(expensesProcess));
                    }
                });
    }

//    @Override
//    public void audit(long expensesInfoId, ShiroUser shiroUser) throws Exception {
//        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
//        logger.info("====货运支出单【{}】审核操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
//        if (!expensesInfo.getEmpId().equals(shiroUser.getId())) {
//            logger.info("====货运支出单审核操作 失败===END===");
//            throw new Exception("非法操作");
//        }
//        // 判断是否是待审核状态
//        if (expensesInfo.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_AUDIT) {
//            logger.info("====货运支出单审核操作 失败===END===");
//            throw new Exception("货运支出单发未处于待审核状态");
//        }
//        // 修改状态为待物流主管审核
//        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), LogisticsConstant.ExpensesStatus.WAIT_LOGISTICS_AUDIT);
//        info.setVersion(expensesInfo.getVersion());
//        int count = expensesInfoMapper.updateById(info);
//        if (count == 0) {
//            logger.info("====货运支出单审核操作（更新失败） 失败===END===");
//            throw new Exception("货运支出单审核操作失败");
//        }
//        // kafka推送
//        OrderProcess orderProcess = new OrderProcess();
//        orderProcess.setActionCode(-1);
//        orderProcess.setInfo(shiroUser.getLoginNo() + " 删除货运支出单【" + expensesInfoId + "】");
//        sendExpenseChange(expensesInfo, JSONObject.toJSONString(orderProcess));
//        // 添加操作记录
//        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser,
//                LogisticsConstant.ExpensesStatus.WAIT_LOGISTICS_AUDIT,
//                LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_LOGISTICS_AUDIT));
//        // kafka推送
//        sendExpenseChange(expensesInfo, actionMsg);
//        logger.info("====货运支出单审核操作 成功===END===");
//    }

//    @Override
//    public void logisticsAudit(long expensesInfoId, String msg, ShiroUser shiroUser) throws Exception {
//        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
//        logger.info("====货运支出单【{}】物流主管审核操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
//        // 判断是否是待物流主管审核状态
//        if (expensesInfo.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_LOGISTICS_AUDIT) {
//            logger.info("====货运支出单物流主管审核操作 失败===END===");
//            throw new Exception("货运支出单发未处于待物流主管审核状态");
//        }
//        // 修改状态为待退款状态
//        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT);
//        info.setVersion(expensesInfo.getVersion());
//        int count = expensesInfoMapper.updateById(info);
//        if (count == 0) {
//            logger.info("====货运支出单物流主管审核操作（更新失败） 失败===END===");
//            throw new Exception("货运支出单物流主管审核操作失败");
//        }
//        // 添加操作记录
//        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser,
//                LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT,
//                LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT), msg);
//        // kafka推送
//        sendExpenseChange(expensesInfo, actionMsg);
//        logger.info("====货运支出单物流主管审核操作 成功===END===");
//    }

    @Override
    public void financeAudit(long expensesInfoId, BigDecimal refundableFee, String msg, ShiroUser shiroUser) throws Exception {
        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
        logger.info("====货运支出单【{}】财务审核操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是待财务审核状态
        if (expensesInfo.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT) {
            logger.info("====货运支出单财务审核操作 失败===END===");
            throw new Exception("货运支出单发未处于待财务审核状态");
        }
        if (refundableFee.compareTo(BigDecimal.ZERO) <= 0) {
            logger.info("====货运支出单结算操作（金额错误） 失败===END===");
            throw new Exception("金额错误");
        }
        // 修改状态为待退款状态
        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), LogisticsConstant.ExpensesStatus.WAIT_REFUND);
        info.setRefundableFee(refundableFee);
        info.setUpdateTime(new Date());
        info.setVersion(expensesInfo.getVersion());
        int count = expensesInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运支出单财务审核操作（更新失败） 失败===END===");
            throw new Exception("货运支出单财务审核操作失败");
        }
        // 添加操作记录
        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser,
                LogisticsConstant.ExpensesStatus.WAIT_REFUND,
                LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_REFUND), msg);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送-处理统计
                        DealExpensesChange dealExpensesChange = new DealExpensesChange(
                                "financeAudit", new Date(), expensesInfo.getEmpId(),
                                logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId()),
                                refundableFee.setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                (expensesInfo.getNowMileage() - expensesInfo.getPreMileage())
                        );
                        kafkaTemplate.send(KafkaTopic.STATISTICS_EXPENSES_CHANGE, "expenses", JSONObject.toJSONString(dealExpensesChange));
                        // kafka推送
                        sendExpenseChange(expensesInfo, shiroUser.getRealName() + "核算了支出单", actionMsg);
                    }
                });
        logger.info("====货运支出单财务审核操作 成功===END===");
    }

//    @Override
//    public void cancel(long expensesInfoId, String msg, ShiroUser shiroUser) throws Exception {
//        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
//        logger.info("====货运支出单【{}】取消操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
//        if (!expensesInfo.getEmpId().equals(shiroUser.getId())) {
//            logger.info("====货运支出单取消操作 失败===END===");
//            throw new Exception("非法操作");
//        }
//        // 判断是否是已取消/待退款
//        if (expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_INVALID ||
//                expensesInfo.getStatus() > LogisticsConstant.ExpensesStatus.WAIT_FINANCE_AUDIT) {
//            logger.info("====货运支出单取消操作（已取消或财务已审核） 失败===END===");
//            throw new Exception("货运支出单已取消或财务已审核禁止操作");
//        }
//        // 此时将货运支出单记录支出单状态改为已存在
//        updateOrderIsBind("直达车", expensesInfo.getToOrderNo(), expensesInfo.getToOrderId(), LogisticsConstant.ExpensesExists.NO_EXISTS);
//        if (expensesInfo.getReturnOrderId() != null) {
//            updateOrderIsBind("回头车", expensesInfo.getReturnOrderNo(), expensesInfo.getReturnOrderId(), LogisticsConstant.ExpensesExists.NO_EXISTS);
//        }
//        // 修改状态为已取消
//        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), LogisticsConstant.ExpensesStatus.ALREADY_INVALID);
//        info.setRemark(msg);
//        info.setVersion(expensesInfo.getVersion());
//        int count = expensesInfoMapper.updateById(info);
//        if (count == 0) {
//            logger.info("====货运支出单取消操作（更新失败） 失败===END===");
//            throw new Exception("货运支出单取消操作失败");
//        }
//        // 添加操作记录
//        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser,
//                LogisticsConstant.ExpensesStatus.WAIT_REFUND,
//                LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.WAIT_REFUND), msg);
//        // kafka推送
//        sendExpenseChange(expensesInfo, actionMsg);
//        logger.info("====货运支出单取消操作 成功===END===");
//    }

    @Override
    public void complete(long expensesInfoId, String evidence, ShiroUser shiroUser) throws Exception {
        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
        logger.info("====货运支出单【{}】结算操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是待退款
        if (expensesInfo.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_REFUND) {
            logger.info("====货运支出单结算操作（状态错误） 失败===END===");
            throw new Exception("货运支出单未处于待退款状态");
        }
        // 修改状态为已完成状态
        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE);
        info.setVersion(expensesInfo.getVersion());
        int count = expensesInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运支出单结算操作（更新失败） 失败===END===");
            throw new Exception("货运支出单结算操作失败");
        }
        // 添加操作记录
        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser,
                LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE,
                LogisticsConstant.ExpensesStatus.getLabel(LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE), null, null, evidence, false);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送-处理统计
                        DealExpensesChange dealExpensesChange = new DealExpensesChange(
                                "complete", new Date(), expensesInfo.getEmpId(),
                                logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId()),
                                expensesInfo.getRefundableFee().setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                (expensesInfo.getNowMileage() - expensesInfo.getPreMileage())
                        );
                        kafkaTemplate.send(KafkaTopic.STATISTICS_EXPENSES_CHANGE, "expenses", JSONObject.toJSONString(dealExpensesChange));
                        // kafka推送
                        sendExpenseChange(expensesInfo, "支出单已结算", actionMsg);
                    }
                });
        logger.info("====货运支出单结算操作 成功===END===");
    }

    @Override
    public void rejected(long expensesInfoId, String msg, ShiroUser shiroUser) throws Exception {
        ExpensesInfo expensesInfo = expensesInfoMapper.selectById(expensesInfoId);
        logger.info("====货运支出单【{}】驳回操作 操作人【{}】===START===", expensesInfo.getNo(), shiroUser.getLoginNo());
        if (expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_INVALID ||
                expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
            logger.info("====货运支出单驳回操作（已完成/已取消禁止操作） 失败===END===");
            throw new Exception("已完成/已取消/禁止操作");
        }
        // 修改状态为上一个状态
        int newStatus = expensesInfo.getStatus() - 1;
        logger.info("===更新货运支出单状态 【{}】=>【{}】", expensesInfo.getStatus(), LogisticsConstant.ExpensesStatus.getLabel(newStatus));
        ExpensesInfo info = new ExpensesInfo(expensesInfo.getId(), newStatus);
        info.setVersion(expensesInfo.getVersion());
        int count = expensesInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运支出单驳回操作（更新失败） 失败===END===");
            throw new Exception("货运支出单驳回操作失败");
        }
        String message = String.format(" 订单状态【%s】=>【%s】驳回理由【%s】",
                LogisticsConstant.ExpensesStatus.getLabel(expensesInfo.getStatus()), LogisticsConstant.ExpensesStatus.getLabel(newStatus), msg);
        // 添加操作记录
        String actionMsg = addExpensesProcess(expensesInfo.getId(), expensesInfo.getNo(), shiroUser, -2,
                "驳回", message, msg, null, true);

        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // 判断驳回前是否是待核算状态，若是回滚修改当日统计数据
                        if (expensesInfo.getStatus() == LogisticsConstant.ExpensesStatus.WAIT_REFUND) {
                            List<ExpensesProcess> expensesProcessList = expensesProcessMapper
                                    .findNewest(expensesInfo.getId(), expensesInfo.getStatus(), LogisticsConstant.ProcessFlag.NEWEST);
                            DealExpensesChange dealExpensesChange = new DealExpensesChange(
                                    "rejected", expensesProcessList.get(0).getCreateTime(), expensesInfo.getEmpId(),
                                    logisticsOrderInfoMapper.findCarIdById(expensesInfo.getToOrderId()),
                                    expensesInfo.getRefundableFee().setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                    (expensesInfo.getNowMileage() - expensesInfo.getPreMileage())
                            );
                            kafkaTemplate.send(KafkaTopic.STATISTICS_EXPENSES_CHANGE, "expenses", JSONObject.toJSONString(dealExpensesChange));
                        }
                        // kafka推送
                        sendExpenseChange(expensesInfo, shiroUser.getRealName() + "驳回了支出单", actionMsg);
                    }
                });
        logger.info("====货运支出单驳回操作 成功===END===");
    }

    @Override
    public IPage<ExpensesAnalyzeVo> findPageAnalyze(QueryParam<ExpensesAnalyzeVo> queryParam) {
        PageParam<ExpensesAnalyzeVo> pageParam = queryParam.toPageParam();
        IPage<ExpensesAnalyzeVo> page = expensesInfoMapper.findPageAnalyze(pageParam.getPage(), pageParam.getEntityWrapper());
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            // 查询所有分类
            QueryWrapper<ExpensesCategory> wrapper = new QueryWrapper<>();
            wrapper.eq("used", CommonConstant.Y);
            wrapper.orderByAsc("sort");
            List<ExpensesCategory> expensesCategoryList = expensesCategoryService.list(wrapper);
            page.getRecords().forEach(expensesAnalyzeVo -> {
                // 计算里程
                expensesAnalyzeVo.setMileage(expensesAnalyzeVo.getNowMileage() - expensesAnalyzeVo.getPreMileage());
                // 计算加油金额
                expensesAnalyzeVo.setFuelTotal(expensesAnalyzeVo.getFuelConsumption().multiply(expensesAnalyzeVo.getFuelPrice()));
                // 处理详情
                expensesAnalyzeVo.setExpensesDetailVoList(dealDetail(expensesCategoryList, expensesAnalyzeVo.getId()));
                // 计算货品
                List<OrderProduct> orderProductList = logisticsOrderProductService.findByOrderId(expensesAnalyzeVo.getOrderId());
                if (!CollectionUtils.isEmpty(orderProductList)) {
                    AtomicReference<String> productName = new AtomicReference<>("");
                    AtomicReference<String> productWeight = new AtomicReference<>("");
                    orderProductList.forEach(orderProduct -> {
                        if (!productName.get().equals("")) {
                            productName.set(productName.get() + ",");
                            productWeight.set(productWeight.get() + ",");
                        }
                        productName.set(productName.get() + orderProduct.getName());
                        productWeight.set(productWeight.get() + orderProduct.getWeight());
                    });
                    expensesAnalyzeVo.setProductName(productName.get());
                    expensesAnalyzeVo.setProductWeight(productWeight.get());
                }
            });
        }
        return page;
    }

    private List<ExpensesDetailVo> dealDetail(List<ExpensesCategory> expensesCategoryList, long expensesId) {
        List<ExpensesDetailVo> expensesDetailVoList = new ArrayList<>();
        AtomicReference<BigDecimal> totalPrice = new AtomicReference<>(BigDecimal.ZERO);
        if (!CollectionUtils.isEmpty(expensesCategoryList)) {
            expensesCategoryList.forEach(expensesCategory -> {
                ExpensesDetailVo expensesDetailVo = new ExpensesDetailVo();
                expensesDetailVo.setTitle(expensesCategory.getName());
                QueryWrapper<ExpensesDetail> wrapper = new QueryWrapper<>();
                wrapper.select("title,price");
                wrapper.eq("category_id", expensesCategory.getId());
                wrapper.eq("expenses_id", expensesId);
                List<ExpensesDetail> expensesDetailList = expensesDetailService.list(wrapper);
                // 处理金额
                AtomicReference<BigDecimal> price = new AtomicReference<>(BigDecimal.ZERO);
                if (!CollectionUtils.isEmpty(expensesDetailList)) {
                    expensesDetailList.forEach(expensesDetail -> {
                        price.set(price.get().add(expensesDetail.getPrice()));
                    });
                }
                // 计算合计
                totalPrice.set(totalPrice.get().add(price.get()));
                expensesDetailVo.setPrice(price.get());
                expensesDetailVoList.add(expensesDetailVo);
            });
        }
        expensesDetailVoList.add(new ExpensesDetailVo("费用合计", totalPrice.get()));
        return expensesDetailVoList;
    }

//    private ExpensesInfo saveExpensesInfo(ExpensesInfo expensesInfo) throws Exception {
//        ExpensesInfo model = new ExpensesInfo();
//        if (expensesInfo.getId() != null) {
//            model = expensesInfoMapper.selectById(expensesInfo.getId());
//            // 只有待审核可修改
//            if (model.getStatus() != LogisticsConstant.ExpensesStatus.WAIT_AUDIT) {
//                logger.info("====保存货运支出单 失败===END===");
//                throw new Exception("只有待审核货运支出单可以修改");
//            }
//            // 非修改项置空
//            model.setNo(null);
//            model.setEmpId(null);
//            model.setToOrderId(null);
//            model.setToOrderNo(null);
//            model.setReturnOrderId(null);
//            model.setReturnOrderNo(null);
//            model.setIsRejected(null);
//            model.setStatus(null);
//        } else {
//            // 判断货运支出单绑定货运单唯一性
//            if (expensesInfoMapper.countByOrderId(expensesInfo.getToOrderId(), LogisticsConstant.OrderLineType.TO_CAR) != 0) {
//                logger.info("====保存货运支出单（直达车货运单已被绑定） 失败===END===");
//                throw new Exception("直达车货运单已被绑定");
//            }
//            if (expensesInfo.getReturnOrderId() != null && expensesInfoMapper.countByOrderId(expensesInfo.getReturnOrderId(), LogisticsConstant.OrderLineType.RETURN_CAR) != 0) {
//                logger.info("====保存货运支出单（回头车货运单已被绑定） 失败===END===");
//                throw new Exception("回头车货运单已被绑定");
//            }
//            // 设置初始化项
//        }
//        // 添加或修改货运订单
//        DataBeanUtils.buildUpdateBean(model, expensesInfo);
//        logger.info("====保存货运支出单基本信息===START===");
//        if (!this.saveOrUpdate(model)) {
//            logger.info("====保存货运支出单基本信息 失败===END===");
//            throw new Exception("货运支出单基本信息保存失败");
//        }
//        // 此时将货运支出单记录支出单状态改为已存在
//        updateOrderIsBind("直达车", expensesInfo.getToOrderNo(), expensesInfo.getToOrderId(), LogisticsConstant.ExpensesExists.YES_EXISTS);
//        if (expensesInfo.getReturnOrderId() != null) {
//            updateOrderIsBind("回头车", expensesInfo.getReturnOrderNo(), expensesInfo.getReturnOrderId(), LogisticsConstant.ExpensesExists.YES_EXISTS);
//        }
//        logger.info("====保存货运支出单基本信息 成功===END===");
//        return model;
//    }

    private BigDecimal saveExpensesDetail(long expensesInfoId, List<ExpensesDetail> expensesDetailList) throws Exception {
        logger.info("====批量保存货运支出单详细信息===START===");
        BigDecimal totalCost = new BigDecimal(0);
        // 获取已存在的详情id集合
        List<Long> oldIdList = expensesDetailMapper.findIdByExpensesInfoId(expensesInfoId);
        List<Long> idList = new ArrayList<>();
        for (ExpensesDetail expensesDetail : expensesDetailList) {
            // 绑定货运支出单
            expensesDetail.setExpensesId(expensesInfoId);
            totalCost = totalCost.add(expensesDetail.getPrice());
            if (expensesDetail.getId() != null) {
                idList.add(expensesDetail.getId());
            }
        }
        boolean flag = this.expensesDetailService.saveOrUpdateBatch(expensesDetailList);
        if (!flag) {
            logger.info("====批量保存货运支出单详细信息 失败===END===");
            throw new Exception("批量保存货运支出单详细信息失败");
        }
        logger.info("====批量保存货运支出单详细信息 成功===START===");

        // 批量删除多余项
        logger.info("====批量删除多余货运支出单详细信息===START===");
        for (Long productId : oldIdList) {
            // 判断传入的id中是否包含已存在的id，若不存在，删除
            if (!idList.contains(productId) && !expensesDetailService.removeById(productId)) {
                logger.info("====批量删除多余货运支出单详细信息 失败===END===");
                throw new Exception("删除多余货运支出单详细信息失败");
            }
        }
        logger.info("====批量删除多余货运支出单详细信息 成功===END===");
        return totalCost;
    }

    private void updateOrderIsBind(String actionName, String orderNo, long orderId, int isBind) throws Exception {
        logger.info("====更新{}货运单【{}】绑定状态===START===", actionName, orderNo);
        OrderInfo info = new OrderInfo(orderId, isBind, logisticsOrderInfoMapper.findVersionById(orderId));
        if (logisticsOrderInfoMapper.updateById(info) == 0) {
            logger.info("====更新直达车货运单绑定状态（更新失败） 失败===END===");
            throw new Exception("系统异常");
        }
        logger.info("====更新直达车货运单绑定状态 成功===END===");
    }

    /**
     * @description: 重写addOrderProcess原方法
     * @author: wzp
     * @date: 2020/5/9
     */
    private String addExpensesProcess(long expensesId, String expensesNo, ShiroUser shiroUser, int actionCode, String actionName) throws Exception {
        return addExpensesProcess(expensesId, expensesNo, shiroUser, actionCode, actionName, null, null, null, false);
    }

    private String addExpensesProcess(long expensesId, String expensesNo, ShiroUser shiroUser, int actionCode, String actionName, String intro) throws Exception {
        return addExpensesProcess(expensesId, expensesNo, shiroUser, actionCode, actionName, null, intro, null, false);
    }

    /**
     * @description: 添加货运单流程记录
     * @param: orderId 货运单id
     * @param: orderNo 货运单号
     * @param: shiroUser 用户信息
     * @param: action 操作编码
     * @param: info 操作信息
     * @return: isRejected 是否是驳回
     * @author: wzp
     * @date: 2020/4/30
     */
    private String addExpensesProcess(long expensesId, String expensesNo, ShiroUser shiroUser, int actionCode, String actionName, String info, String intro, String credentials, boolean isRejected) throws Exception {
        logger.info("====保存货运支出单操作流程===START===");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowDate = simpleDateFormat.format(new Date());
        if (info == null) {
            info = String.format("员工【%s】%s 进行【%s】操作", shiroUser.getRealName(), nowDate, actionName);
        }
        // 获取最新操作记录
        if (!isRejected) {
            List<ExpensesProcess> expensesProcessList = expensesProcessMapper.findNewest(expensesId, actionCode, LogisticsConstant.ProcessFlag.NEWEST);
            // 更新历史记录
            for (ExpensesProcess expensesProcess : expensesProcessList) {
                logger.info("====保存货运支出单操作流程历史 ===START===");
                ExpensesProcess process = new ExpensesProcess();
                process.setId(expensesProcess.getId());
                process.setFlag(LogisticsConstant.ProcessFlag.HISTORY);
                process.setVersion(expensesProcess.getVersion());
                if (expensesProcessMapper.updateById(process) == 0) {
                    logger.info("====保存货运支出单操作流程历史 失败===START===");
                    throw new Exception("保存货运支出单操作流程历史失败");
                }
                logger.info("====保存货运支出单操作流程历史 成功===START===");
            }
        }
        // 添加新的操作记录
        ExpensesProcess expensesProcess = new ExpensesProcess(expensesId, expensesNo, shiroUser, actionCode, actionName, info, intro, credentials);
        if (expensesProcessMapper.insert(expensesProcess) == 0) {
            logger.info("====保存货运支出单操作流程 失败===START===");
            throw new Exception("保存货运支出单操作流程失败");
        }
        logger.info("====保存货运支出单操作流程 成功===START===");
        return JSONObject.toJSONString(expensesProcess);
    }

    private void sendExpenseChange(ExpensesInfo expensesInfo, String message, String msg) {
        logger.info("===推送货运支出订单...");
        OrderDto<ExpensesInfo> param = new OrderDto<>(OrderType.EXPENSE_ORDER, expensesInfo, msg, message);
        kafkaTemplate.send(KafkaTopic.LOGISTICS_EXPENSES_CHANGE, expensesInfo.getId().toString(), JSONObject.toJSONString(param));
    }

}
